﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Management;
using System.Security.Cryptography;
using System.Windows.Forms;

namespace cmdrunner
{
    internal class Util
    {

        public static ProcessInfo FindProcess(int pid, bool withChildren)
        {
            if (pid < 0)
            {
                return null;
            }

            ManagementObjectCollection list = WMIUtil.Execute("SELECT * FROM Win32_Process WHERE ProcessId = " + pid);
            if (list.Count == 0)
            {
                return null;
            }

            foreach (ManagementObject o in list)
            {
                ProcessInfo info = new ProcessInfo();
                info.Id = Convert.ToInt32(o["ProcessId"]);
                info.Name = Convert.ToString(o["Name"]);
                info.ParentId = Convert.ToInt32(o["ParentProcessId"]);
                if (withChildren)
                {
                    info.Children = FindChildren(info.Id);
                }
                return info;
            }

            return null;
        }

        public static ProcessInfo FindProcess(int pid)
        {
            return FindProcess(pid, false);
        }


        public static List<ProcessInfo> FindChildren(int pid)
        {
            if (pid <= 0)
            {
                return new List<ProcessInfo>(0);
            }

            List<ProcessInfo> result = new List<ProcessInfo>();

            ManagementObjectCollection list = WMIUtil.Execute("SELECT * FROM Win32_Process WHERE ParentProcessId = " + pid);

            foreach (ManagementObject o in list)
            {
                ProcessInfo info = new ProcessInfo();
                info.Id = Convert.ToInt32(o["ProcessId"]);
                info.Name = Convert.ToString(o["Name"]);
                info.ParentId = Convert.ToInt32(o["ParentProcessId"]);
                info.Children = FindChildren(info.Id);
                result.Add(info);
            }

            return result;

        }

        public static List<ProcessInfo> FindParents(int pid)
        {
            List<ProcessInfo> result = new List<ProcessInfo>();

            ProcessInfo p = FindProcess(pid);

            if (p == null)
            {
                return result;
            }

            ProcessInfo parent = FindProcess(p.ParentId, false);

            while (parent != null)
            {
                result.Add(parent);

                if (parent.Id == 0)
                {
                    break;
                }
                parent = FindProcess(parent.ParentId, false);
            }

            result.Reverse();
            return result;

        }
        public static void CloseProcess(int pid, bool withChildren)
        {
            ProcessInfo process = FindProcess(pid);

            if (process == null)
            {
                return;
            }

            if (withChildren)
            {
                foreach (ProcessInfo child in FindChildren(pid))
                {
                    CloseProcess(child.Id, true);
                }
            }

            Process p = null;
            try
            {
                p = Process.GetProcessById(pid);
            }
            catch (Exception)
            {
                // 进程已经不存在时，GetProcessById 会报错
            }
            if (p != null && !p.HasExited)
            {
                try
                {
                    p.Kill();
                }
                catch (Win32Exception)
                {
                    throw new StopProcessFailException("无法终止相关联的进程。" + pid);
                }
                catch (NotSupportedException)
                {
                    throw new StopProcessFailException("终你正尝试为远程计算机上运行的进程调用 Kill()。 该方法仅对本地计算机上运行的进程可用。" + pid);
                }
                catch (InvalidOperationException)
                {
                    throw new StopProcessFailException("没有与此 Process 对象关联的进程。" + pid);
                }
            }
        }

        public static bool ConfirmBox(String msg, String title)
        {
            DialogResult dialogResult = MessageBox.Show(msg, title, MessageBoxButtons.OKCancel);
            return dialogResult == DialogResult.OK;
        }
    }


}
